#include "LKMRootkit_Detect.h"


/* -----------  内核线程task_struct声明 START-----------------*/
static struct task_struct *detect_rootkit_kthread = NULL;
/* -----------  内核线程task_struct声明 END -----------------*/



/* --------------- 需要获取的内核符号声明 START ------------------- */
static kallsyms_lookup_name_t k_kallsyms_lookup_name = NULL;
static core_kernel_text_t k_core_kernel_text = NULL;
static unsigned long ** k_sys_call_table = NULL;
static struct kset *k_module_kset = NULL;
static struct mutex *k_module_mutex = NULL;
static find_module_t k_find_module = NULL;
static __module_address_t k___module_address = NULL;
static insn_init_t k_insn_init = NULL;
static insn_get_length_t k_insn_get_length = NULL;
static insn_get_opcode_t k_insn_get_opcode = NULL;
static insn_get_immediate_t k_insn_get_immediate = NULL;
static insn_get_modrm_t k_insn_get_modrm = NULL;
static insn_get_sib_t k_insn_get_sib = NULL;
static insn_get_displacement_t k_insn_get_displacement = NULL;
static insn_get_prefixes_t k_insn_get_prefixes = NULL;

/* --------------- 需要获取的内核符号声明 END ------------------- */



/* --------------- 需要检查的项 START -------------------*/
static char kernel_func_list[MAX_KERNEL_FUNC][MAX_SYMBOL_LEN] = 
{
    "copy_creds", "exit_creds", "audit_alloc", "vfs_statx", "find_task_by_vpid", "sys_kill", 
    "__x64_sys_kill", "next_tgid", "fillonedir", "filldir", "filldir64", "compat_fillonedir",
    "compat_filldir", "compat_filldir64", "__d_lookup", "vfs_read", "tcp4_seq_show", 
    "udp4_seq_show", "ip_rcv", "load_elf_binary", "inet_ioctl"
}; // 需要检查的函数列表
static int kernel_func_status[MAX_KERNEL_FUNC]={0}; // 需要检查的内核函数状态 0 正常 1 劫持
static int kernel_func_num = 21; // 需要检查的函数列表的长度
static int insn_check_list[MAX_INSN_NUM] = {
    0xE9, // jump
    0xE8, // call
    0xFF
}; // 需要检查的跳转指令列表
static int insn_check_num = 3; // 需要检查的跳转指令列表的长度
static int insn_search_length_list[MAX_SEERCH_DEPTH]; // 维护往下遍历所有指令的长度，便于回溯
static int insn_check_depth = 0;
/* --------------- 需要检查的项 END -------------------*/


/* ------------------ 维护列表 START --------------------*/
static int sct_error_index[NR_syscalls] = {0}; // 系统调用表错误下标数组
static int sct_error_length = 0; // 系统调用表错误下标数组长度
static char hide_module_list[MAX_HIDE_MODULE][MAX_SYMBOL_LEN]; // 隐藏内核模块维护列表
static int hide_module_num = 0; // 隐藏内核模块维护列表的长度
/* ------------------ 维护列表 END --------------------*/



/*--------------------- 所需函数编写 START ------------------------*/

// 找到内核符号 name 对应的地址
// 流程：kprobe 得到 kallsyms_lookup_name 的地址 -> kallsyms_lookup_name(name)得到 name 对应
unsigned long my_kallsyms_lookup_name(const char *name){
    if(k_kallsyms_lookup_name == NULL){ // 如果直接获取失败，则用kprobe方式
        kp.symbol_name = "kallsyms_lookup_name"; // 传入内核符号名
        if(!register_kprobe(&kp)){ // 如果返回0，注册成功
            k_kallsyms_lookup_name = (kallsyms_lookup_name_t)kp.addr; // 获取kallsmy_lookup_name函数地址
            unregister_kprobe(&kp); // 取消探测点
        }
    }
    // 调用orig_kallsyms_lookup_name
    return k_kallsyms_lookup_name ? k_kallsyms_lookup_name(name) : 0;
}

// 获取全部所需的内核符号
static void get_all_symbol_addr(void){
    struct kset **kset;

    k_core_kernel_text = (core_kernel_text_t)my_kallsyms_lookup_name("core_kernel_text");
    k_sys_call_table = (void *)my_kallsyms_lookup_name("sys_call_table");
    k_module_mutex = (void *)my_kallsyms_lookup_name("module_mutex");
    k_find_module = (find_module_t)my_kallsyms_lookup_name("find_module");
    k___module_address = (__module_address_t)my_kallsyms_lookup_name("__module_address");
    kset = (void *)my_kallsyms_lookup_name("module_kset"); // 获取地址并解引用
    if(kset) k_module_kset = *kset;
    k_insn_init = (insn_init_t)my_kallsyms_lookup_name("insn_init");
    k_insn_get_length = (insn_get_length_t)my_kallsyms_lookup_name("insn_get_length");
    k_insn_get_opcode = (insn_get_opcode_t)my_kallsyms_lookup_name("insn_get_opcode");
    k_insn_get_immediate = (insn_get_immediate_t)my_kallsyms_lookup_name("insn_get_immediate");
    k_insn_get_modrm = (insn_get_modrm_t)my_kallsyms_lookup_name("insn_get_modrm");
    k_insn_get_sib = (insn_get_sib_t)my_kallsyms_lookup_name("insn_get_sib");
    k_insn_get_displacement = (insn_get_displacement_t)my_kallsyms_lookup_name("insn_get_displacement");
    k_insn_get_prefixes = (insn_get_prefixes_t)my_kallsyms_lookup_name("insn_get_prefixes");
}


// ----------- 获取某地址指令信息系列函数 START------------- //
// 初始化地址p处的insn结构体，获取全部信息
// 流程：获取64位/32位 -> 确定内核版本范围 -> 调用init获取地址p处的指令insn结构体
static void my_init_insn(struct insn* insn_adr,const void *p){
    int x86_64 = 0;
    #ifdef CONFIG_X86_64
        x86_64 = 1;
    #endif

    #if defined MAX_INSN_SIZE && (MAX_INSN_SIZE == 15) /* 3.19.7+ */
        k_insn_init(insn_adr, p, MAX_INSN_SIZE, x86_64);
    #else
        k_insn_init(insn_adr, p, x86_64);
    #endif

    k_insn_get_length(insn_adr); // length
    k_insn_get_prefixes(insn_adr); // prefixes
    k_insn_get_opcode(insn_adr); //opcode
    k_insn_get_modrm(insn_adr); //modrm
    k_insn_get_sib(insn_adr); // sib
    k_insn_get_displacement(insn_adr); // displacement
    k_insn_get_immediate(insn_adr); // immediate

}

// 找到第一条在指令检测列表中的跳转指令并返回地址
static char * get_check_insn_in_list(const void *p){
    struct insn cur_insn; // 当前指令

    char * cur_insn_addr; // 当前指令的地址
    int in_insn_check_list; // 当前指令在检查列表中
    int insn_i; // 用于遍历检查列表

    // 第一条指令地址获取
    cur_insn_addr = p;

    // 清空数组
    memset(insn_search_length_list, 0, sizeof(insn_search_length_list));
    insn_check_depth = 0;


    do{ // 当前指令不在检查列表中
        my_init_insn(&cur_insn, (const void *)cur_insn_addr);

        insn_search_length_list[insn_check_depth] = cur_insn.length; // 遍历的时候纳入指令长度
        insn_check_depth += 1; // 深度更新

        in_insn_check_list = 0;
        for(insn_i = 0 ; insn_i < insn_check_num; insn_i++){ // 遍历一下检查列表
            if(cur_insn.opcode.value==insn_check_list[insn_i]) // 出现在检查列表中
                if(cur_insn.opcode.value==0xFF){
                    if(cur_insn.modrm.value>=0xd0 && cur_insn.modrm.value<=0xe7){
                        in_insn_check_list = 1;
                    }
                }
                else in_insn_check_list = 1;
        }
        if(!in_insn_check_list){ // 如果不在检查列表中
            cur_insn_addr = cur_insn_addr + cur_insn.length; // 更新为下一条指令地址
        }
    }while(!in_insn_check_list);

    // DBG_NUM("insn_check_depth", insn_check_depth);

    // 找到了跳出循环
    return cur_insn_addr;
}


// 获取某一个跳转指令的目标跳转地址
static char * get_insn_jump_target_addr(const void *p){
    struct insn cur_insn; // 当前指令
    int movabs_rd; // moveabs的操作码偏移
    int movabs_opcode; // moveabs的操作码
    char * cur_insn_addr; // 当前指令的地址
    int check_i; // 用于溯源遍历
    long target_addr; // 跳转的目标地址

    cur_insn_addr = p; 
    my_init_insn(&cur_insn, cur_insn_addr); // 出初始化指令

    // 可拓展
    if(cur_insn.opcode.value==0xE9 || cur_insn.opcode.value==0xE8){ // call 和 jump
        target_addr = (char *)(cur_insn.immediate.value + cur_insn_addr + 5);
        return target_addr;
    }
    else if(cur_insn.opcode.value==0xFF){ // call or jump
        switch(cur_insn.modrm.value){ // 选择movabs_rd
            case 0xd0: movabs_rd=0; break;
            case 0xd1: movabs_rd=1; break;
            case 0xd2: movabs_rd=2; break;
            case 0xd3: movabs_rd=3; break;
            case 0xd4: movabs_rd=4; break;
            case 0xd5: movabs_rd=5; break;
            case 0xd6: movabs_rd=6; break;
            case 0xd7: movabs_rd=7; break;
            case 0xd8: movabs_rd=0; break;
            case 0xd9: movabs_rd=1; break;
            case 0xda: movabs_rd=2; break;
            case 0xdb: movabs_rd=3; break;
            case 0xdc: movabs_rd=4; break;
            case 0xdd: movabs_rd=5; break;
            case 0xde: movabs_rd=6; break;
            case 0xdf: movabs_rd=7; break;
            case 0xe0: movabs_rd=0; break;
            case 0xe1: movabs_rd=1; break;
            case 0xe2: movabs_rd=2; break;
            case 0xe3: movabs_rd=3; break;
            case 0xe4: movabs_rd=4; break;
            case 0xe5: movabs_rd=5; break;
            case 0xe6: movabs_rd=6; break;
            case 0xe7: movabs_rd=7; break;
            default:movabs_rd=0; break;
        }
        movabs_opcode = 0xb8 + movabs_rd; // 得到要溯源的movabs_opcode
        // 往前找10条指令
        for(check_i=0; check_i<insn_check_depth; check_i++){
            my_init_insn(&cur_insn, (const void *)cur_insn_addr);

            if(cur_insn.opcode.value!=movabs_opcode || cur_insn.rex_prefix.value!=0x48){ // 如果不在检查列表中
                if((insn_check_depth-check_i-1)>0) 
                    cur_insn_addr = cur_insn_addr - insn_search_length_list[insn_check_depth-check_i-2]; // 更新为上一条指令地址
            }else{
                target_addr = cur_insn.immediate2.value;
                target_addr = (target_addr << 32) + (unsigned int)cur_insn.immediate1.value;
                return (char*)(target_addr);
            }
        }
    }

    return NULL;

}
// ----------- 获取某地址指令信息系列函数 END------------- //

// 根据内核模块主地址获取对应的内核模块
static const char * get_module_from_core_addr(unsigned long addr){
    struct module * ret_module; // 待返回的结构体

    if(!k_module_mutex) {
        return NULL;
    }
    
    if(!k___module_address) return NULL;
    mutex_lock(k_module_mutex); // 模块加锁
    ret_module = k___module_address(addr); // 尝试借助__module_address()函数查询
    if(ret_module){ // 查询成功
        mutex_unlock(k_module_mutex); // 模块解锁 
        return ret_module->name; // 返回名字
    }else{ // 查询失败，对应模块可能被隐藏，或者为恶意模块
        struct kobject *cur_kobj;
        struct module_kobject *cur_module_kobj;

        if(!k_module_kset) { 
            mutex_unlock(k_module_mutex); // 模块解锁 
            return NULL;
        }

        spin_lock(&k_module_kset->list_lock);// 加锁访问
        list_for_each_entry(cur_kobj, &k_module_kset->list, entry){ // 遍历module_kset，当前结点是cur_kobj
            if(!kobject_name(cur_kobj)){ // cur_obj名字为空，跳
                break;
            }

            // 获取包含cur_kobj的cur_module_kobj
            cur_module_kobj = container_of(cur_kobj, struct module_kobject, kobj);

            if(!cur_module_kobj) continue;
            if(!cur_module_kobj->mod) continue;
            if(!cur_module_kobj->mod->name) continue;
            if(within_module(addr, cur_module_kobj->mod)){ // 寻找对应模块
                spin_unlock(&k_module_kset->list_lock); // 退出解锁
                mutex_unlock(k_module_mutex); // 模块解锁
                return cur_module_kobj->mod->name;
            }
        }
        spin_unlock(&k_module_kset->list_lock); // 退出解锁
    }
    mutex_unlock(k_module_mutex); // 模块解锁
    return NULL;
}

// 根据内核模块可执行数据段地址溯源相关的内核模块
static const char * get_relative_module_from_data_addr(unsigned long data_func_addr){
    struct insn cur_insn; // 当前指令

    struct module * ret_module; // 待返回的结构体

    char * insn_check_addr; // 可执行数据段第一个跳转指令地址
    char * jump_target_addr; // 跳转的目标地址
    int test_i; // 用于循环打印的变量

    insn_check_addr = get_check_insn_in_list((const void*)data_func_addr);

    jump_target_addr = get_insn_jump_target_addr((const void*)insn_check_addr);

    return get_module_from_core_addr((unsigned long)jump_target_addr);    
}

// 根据可疑地址尝试溯源对应内核模块
static const char * get_module_from_addr(unsigned long addr){
    char * ret_module_name; // 待返回的结构体
    ret_module_name = get_module_from_core_addr(addr);
    if(ret_module_name==NULL) ret_module_name = get_relative_module_from_data_addr(addr);
    return ret_module_name;
}


/*--------------------- 所需函数编写 END -----------------------*/




/*--------------------- 核心流程 START ------------------------*/

// 检查系统调用表的地址
static void check_syscall_addr(void){
    int syscall_i; // 用于遍历系统调用表
    int syscall_j; // 用于遍历维护列表
    int error_add; // 新增加的错误个数
    int in_error_flag; // 当前下标不在维护列表中
    const char * module_name = NULL; // 修改系统调用表的内核模块名字
    error_add=0;
    in_error_flag=0;

    if(!k_sys_call_table) return;

    for(syscall_i=0;syscall_i<NR_syscalls;syscall_i++){
        // 每隔1s遍历一次系统调用表
        if(!k_core_kernel_text((long)(t_syscall)(k_sys_call_table[syscall_i]))){
            // 发现错误系统调用
            for(syscall_j=0;syscall_j<sct_error_length;syscall_j++){
                // 遍历系统调用表错误下标数组
                if(sct_error_index[syscall_j]==syscall_i) in_error_flag=1; // 当前下标在维护列表中
            }
            if(!in_error_flag){ // 当前下标不在维护列表中，加入维护列表
                sct_error_index[sct_error_length] = syscall_i;
                sct_error_length += 1;
                error_add += 1;
            }
            in_error_flag = 0; // 为下一个复位
        }
    }

    if(error_add!=0){ // 出现新的就全部打印一次
        for(syscall_i=0;syscall_i<sct_error_length;syscall_i++){
            if(syscall_i==0) {
                printk("Rootkit Is Detected: Syscall Table Hook!\n");
            }
            module_name = get_module_from_addr(
                (unsigned long)(t_syscall)(k_sys_call_table[sct_error_index[syscall_i]]));
            printk("error: Hack Syscall:__sys_call_table[%d]=%lx Rootkit Module:%s",
                    sct_error_index[syscall_i],
                    (long)(t_syscall)(k_sys_call_table[sct_error_index[syscall_i]]),
                    module_name);
            //name
        }
    }

}

// 检查是否存在隐藏模块
static void check_hidden_module(void){
    int module_i; // 用于遍历隐藏模块维护列表
    int in_hide_module_list; // 标记是否在维护列表中
    int hide_module_add; // 本次添加的个数
    struct kobject *cur_kobj;
	struct module_kobject *cur_module_kobj;
    hide_module_add=0;

    in_hide_module_list=0;

    if(!k_module_kset) return;
    if(!k_find_module) return;


    spin_lock(&k_module_kset->list_lock);// 加锁访问
    hide_module_add=0;
    list_for_each_entry(cur_kobj, &k_module_kset->list, entry){ // 遍历module_kset，当前结点是cur_kobj
        if(!kobject_name(cur_kobj)){ // cur_obj名字为空，跳
            break;
        }

        // hide_module_add is 0 here
        // 获取包含cur_kobj的cur_module_kobj
        cur_module_kobj = container_of(cur_kobj, struct module_kobject, kobj);

        if(!cur_module_kobj) continue;
        if(!cur_module_kobj->mod) continue;
        if(!cur_module_kobj->mod->name) continue;

        if(!k_find_module(cur_module_kobj->mod->name)){ // 找到隐藏模块
            for(module_i=0; module_i<hide_module_num; module_i++){
                if(!memcmp(&hide_module_list[module_i], &cur_module_kobj->mod->name, 
                            sizeof(cur_module_kobj->mod->name))){
                    in_hide_module_list = 1; // 在维护列表中
                }
            }

            if(!in_hide_module_list){ // 不在维护列表中，则加入
                memcpy(&hide_module_list[hide_module_num], &cur_module_kobj->mod->name,
                         sizeof(cur_module_kobj->mod->name));
                // only once
                hide_module_num += 1;
                hide_module_add += 1;
            }

            in_hide_module_list=0; // 为下一个复位
        }
    }
    spin_unlock(&k_module_kset->list_lock); // 退出解锁

    if(hide_module_add!=0){ // 有新增则全部打印
        // but twice here
        for(module_i=0; module_i<hide_module_num; module_i++){
            if(module_i==0) {
                printk("Rootkit Is Detected: Hide Module Detect!\n");
            }
            printk("error: Hide Module: %s \n", hide_module_list[module_i]);
            //name
        }
    }
}

// 检查内核函数代码是否被劫持
static void check_kernel_func_insn(void){
    struct insn cur_insn; // 当前指令
    char * kernel_func_addr; // 内核函数的入口地址
    char * insn_check_addr; // 内核函数第一个跳转指令地址
    char * jump_target_addr; // 跳转的目标地址
    int func_i; // 用于遍历检查内核函数列表
    // int insn_check_length; // 内核函数第一个跳转指令地址的长度 调试
    // struct insn_field insn_check_opcode; // 内核函数第一个跳转指令地址的操作码 调试
    struct insn_field insn_check_immediate; // 内核函数第一个跳转指令地址的立即数
    const char * module_name = NULL; // 修改内核函数的内核模块名字

    for(func_i=0;func_i<kernel_func_num;func_i++){
        // 找到内核函数的入口地址
        kernel_func_addr = (void *)(my_kallsyms_lookup_name(kernel_func_list[func_i]));
        if(kernel_func_addr!=NULL){ // 不为空
            // 找到第一个为E9或E8的指令
            insn_check_addr = get_check_insn_in_list((const void *)kernel_func_addr);
            // 初始化该指令
            my_init_insn(&cur_insn, (const void *)insn_check_addr);
            // 获取指令立即数
            jump_target_addr = get_insn_jump_target_addr((const void *)insn_check_addr);
            if(!k_core_kernel_text((unsigned long)jump_target_addr)){
                // 检查到内核函数代码被修改
                if(kernel_func_status[func_i]==0){
                    if(func_i==0) printk("Rootkit Is Detected: Kernel Func Hook!\n");
                    module_name = get_module_from_addr((unsigned long)jump_target_addr);
                    printk("error: Hack Kernel Func:%s Rootkit Module:%s",
                        kernel_func_list[func_i], module_name);
                }
                kernel_func_status[func_i] = 1; // 标记位改为1
            }else{
                kernel_func_status[func_i] = 0; // 标记位改为0
            }
        }
    }

}

// 编写rootkit检测内核任务 1s一次
static int detect_rootkit(void *argv){
    while (!kthread_should_stop()) {
        check_syscall_addr(); // 系统调用表修改
        check_hidden_module(); // 隐藏模块
        check_kernel_func_insn(); // 内核函数代码修改
        msleep(1000);
	}
    do_exit(0);
    return 0;
}

/*--------------------- 核心流程 END ------------------------*/



/*--------------------- 内核模块 START ------------------------*/

// 内核模块检测程序 入口
static int __init kprobe_init(void)
{
	INFO("### Rootkit Dectection Start ###");
    get_all_symbol_addr();

    // 创建内核工作线程并运行
	detect_rootkit_kthread = kthread_run(detect_rootkit, NULL, "kthread-detect-rootkit");  
	if (!detect_rootkit_kthread) {
		ERR("kthread_run fail");
		return -ECHILD;
	}

	return 0;
}

// 内核模块检测程序 退出
static void __exit kprobe_exit(void)
{
	if (detect_rootkit_kthread) {
		kthread_stop(detect_rootkit_kthread); //停止内核线程
		detect_rootkit_kthread = NULL;
	}
	INFO("### Rootkit Dectection End ###");
}

module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL");

/*--------------------- 内核模块 END ------------------------*/
